﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using NLog;
using RunUI.Attributes;

namespace RunUI
{
    [ApiController]
    [Route("[controller]/[action]")]
    public abstract class BaseController : ControllerBase, IAsyncActionFilter, IActionFilter
    {

        protected Logger CurrLogger { get; } = LogManager.GetCurrentClassLogger();


        protected IPathProvider Server { get; private set; }

        protected string UserId { get; set; }


        public BaseController()
        {
            Server = GlobalValues.ServiceProvider.GetService<IPathProvider>();

            if (User?.Identity?.IsAuthenticated == true)
            {
                UserId = User.Identity.Name;
            }
        }

        protected virtual PagedListResult<T> Ok<T>(PagedList<T> rows)
        {
            var result = new PagedListResult<T>
            {
                List = rows,
                Select = new List<SelectInfo>()
            };
            var properties = typeof(T).GetProperties();

            foreach (var property in properties)
            {
                if (property.PropertyType.IsEnum || property.PropertyType.IsEnumNullable())
                {
                    var enumType = property.PropertyType.IsEnum ? property.PropertyType : property.PropertyType.GetGenericArguments()[0];

                    result.Select.Add(new SelectInfo
                    {
                        Name = property.Name,
                        Type = enumType.FullName,
                        SelectType = AppEnum.SelectType.Enum,
                    });
                }
                else if (property.IsPropertyHasAttribute<ForeignEnumAttribute>(out var attr))
                {
                    result.Select.Add(new SelectInfo
                    {
                        Name = property.Name,
                        Type = attr.EnumCode,
                        SelectType = AppEnum.SelectType.EnumDict
                    });
                }
                else if (property.IsPropertyHasAttribute<ForeignRelationAttribute>(out var attr1))
                {
                    result.Select.Add(new SelectInfo
                    {
                        Name = property.Name,
                        Type = attr1.Table.FullName,
                        SelectType = AppEnum.SelectType.Relation
                    });
                }
            }


            return result;
        }

        [NonAction]
        public virtual Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (next == null)
            {
                throw new ArgumentNullException(nameof(next));
            }

            OnActionExecuting(context);
            if (context.Result == null)
            {
                var task = next();
                if (!task.IsCompletedSuccessfully)
                {
                    return Awaited(this, task);
                }

                OnActionExecuted(task.Result);
            }

            return Task.CompletedTask;

            static async Task Awaited(BaseController controller, Task<ActionExecutedContext> task)
            {
                controller.OnActionExecuted(await task);
            }
        }

        [NonAction]
        public virtual void OnActionExecuting(ActionExecutingContext context)
        {

        }
        [NonAction]
        public virtual void OnActionExecuted(ActionExecutedContext context)
        {
        }
    }
}
